namespace CCStatistics.Domain.Api
{
    using System;
    using System.Text.RegularExpressions;
    using System.Xml.XPath;

    using ThoughtWorks.CruiseControl.Core;
    using ThoughtWorks.CruiseControl.Remote;

    /// 
    ///         This is a wrapper class to create an IntegrationResult from the raw XML log that was generated
    ///         at the time this integration was performed. We iterate over all the log files, create a=custom 
    ///         Integration Result (in this class) and then pass it to our override CCStatisticsPublisher
    ///         which we use instead of the StatisticsPublisher (part of the Core CC framework).
    /// 
    ///         This class was pulled out to better focus on the single responsibility design goal for classes.
    /// 
    ///         RESPONSIBILITY: Given an XML Log, Create a new IntegrationResult instance. 
    /// 
    /// 
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    public static class IntegrationResultHelper
    {
        private static readonly Regex _regexMatchName = new Regex(@"log\d+Lbuild\.(?<Label>.*)\.xml",
                                                                  RegexOptions.Compiled);

        /// <summary>
        /// Gets the results from the specified log file name.
        /// </summary>
        /// <param name="logFileName">Name of the log file.</param>
        /// <param name="logXml">The log XML.</param>
        /// <param name="workingDirectory">The working directory.</param>
        /// <param name="artifactDirectory">The artifact directory.</param>
        /// <param name="expectedNextLabel">The expected next build label, usually derived from a previous successful build of the project</param>
        /// <returns></returns>
        public static IntegrationResult Result(string logFileName,
                                               XPathNavigator logXml,
                                               String workingDirectory,
                                               String artifactDirectory,
                                               int expectedNextLabel)
        {
            var _integrationResult = new IntegrationResult();

            SetIntegrationResult(_integrationResult, logXml);
            SetBuildLabel(_integrationResult, logFileName, expectedNextLabel);

            _integrationResult.WorkingDirectory = workingDirectory;
            _integrationResult.ArtifactDirectory = artifactDirectory;

            return _integrationResult;
        }

        private static void SetBuildLabel(IIntegrationResult integrationResult, String logFileName, int expectedNextLabel)
        {
            var buildLabel = "";

            var match = _regexMatchName.Match(logFileName);

            if (match.Success)
                buildLabel = match.Groups["Label"].Value;

            if (String.IsNullOrEmpty(buildLabel))
            {
                buildLabel = expectedNextLabel.ToString();
                integrationResult.Status = IntegrationStatus.Failure;
            }
            integrationResult.Label = buildLabel;
        }

        private static void SetIntegrationResult(IIntegrationResult integrationResult, XPathNavigator logXml)
        {
            var buildNode = logXml.SelectSingleNode(@"//cruisecontrol/build");

            integrationResult.StartTime = DateTime.Parse(buildNode.GetAttribute("date", ""));

            var result = buildNode.SelectSingleNode("@error");
            if (result != null && result.Value == "true")
                integrationResult.Status = IntegrationStatus.Failure;
            else if (result != null && result.Value == "false")
                integrationResult.Status = IntegrationStatus.Success;
            else
            {
                // Initial Value if no error count found
                integrationResult.Status = IntegrationStatus.Unknown;

                var oErrorCount = buildNode.SelectSingleNode("//@error_count");

                if (oErrorCount != null)
                {
                    var iErrorCount = Convert.ToInt32(oErrorCount.Value);
                    SetIntegrationStatusByErrorCount(integrationResult, iErrorCount);
                }
            }
        }

        private static void SetIntegrationStatusByErrorCount(IIntegrationResult integrationResult, int iErrorCount)
        {
            integrationResult.Status = iErrorCount == 0 ? IntegrationStatus.Success : IntegrationStatus.Failure;
        }
    }
}